// $Id: Table.cs 71 2008-06-24 20:21:42Z nvivo $

using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using System.Xml;
using System.Xml.XPath;

namespace DBLGen
{
	/// <summary>
	/// Represents a table from a database.
	/// </summary>
	[System.Diagnostics.DebuggerDisplay("Table: {QualifiedName}")]
	[DefaultProperty("Alias")]
	public sealed class Table
	{
		public Table()
		{
			_columns = new ColumnCollection(this);
			_methods = new MethodCollection(this);
		}

		private Guid _uniqueID = Guid.Empty;
		private Project _project;

		private string _schema;
		private string _name;
		private TableSourceType _sourceType;
		private ColumnCollection _columns;
		private MethodCollection _methods;

		private string _alias;
		private string _comments;

		private bool _canExport = true;
		private CustomAttributes _customAttributes;

		[Browsable(false)]
		public Guid UniqueID
		{
			get
			{
				if (_uniqueID == Guid.Empty)
					_uniqueID = Guid.NewGuid();

				return _uniqueID;
			}
			private set
			{
				_uniqueID = value;
			}
		}

		/// <summary>
		/// Gets the project that owns this table.
		/// </summary>
		[Browsable(false)]
		public Project Project
		{
			get
			{
				return _project;
			}
			internal set
			{
				_project = value;
			}
		}

		/// <summary>
		/// Gets or sets the table schema.
		/// </summary>
		[Category("Database")]
		[TypeConverter(typeof(UI.Design.TableIdentifierTypeConverter))]
		public string Schema
		{
			get
			{
				return _schema ?? String.Empty;
			}
			set
			{
				_schema = value;
			}
		}

		/// <summary>
		/// Gets or sets the table name.
		/// </summary>
		[Category("Database")]
		[TypeConverter(typeof(UI.Design.TableIdentifierTypeConverter))]
		public string Name
		{
			get
			{
				return _name ?? String.Empty;
			}
			set
			{
				_name = value;
			}
		}

		/// <summary>
		/// Gets or sets the type of source this table came from.
		/// </summary>
		[Category("Database")]
		public TableSourceType SourceType
		{
			get
			{
				return _sourceType;
			}
			set
			{
				_sourceType = value;
			}
		}

		/// <summary>
		/// Gets the qualified name of this table (Schema.Name)
		/// </summary>
		[Category("Database")]
		[ReadOnly(true)]
		public string QualifiedName
		{
			get
			{
				if (!String.IsNullOrEmpty(Schema))
					return Schema + "." + Name;
				else
					return Name;
			}
		}

		[Category("Code")]
		public string Alias
		{
			get
			{
				return _alias ?? String.Empty;
			}
			set
			{
				_alias = value;
			}
		}

		[Category("Code")]
		public string Comments
		{
			get
			{
				return _comments ?? String.Empty;
			}
			set
			{
				_comments = value;
			}
		}

		[Category("Code")]
		[Description("Defines if the table can be exported.")]
		public bool CanExport
		{
			get
			{
				return _canExport;
			}
			set
			{
				_canExport = value;
			}
		}

		[Category("Code")]
		public CustomAttributes CustomAttributes
		{
			get
			{
				if (_customAttributes == null)
					_customAttributes = new CustomAttributes();

				return _customAttributes;
			}
			set
			{
				_customAttributes = value;
			}
		}

		/// <summary>
		/// Gets the columns for this table.
		/// </summary>
		[Browsable(false)]
		public ColumnCollection Columns
		{
			get
			{
				return _columns;
			}
		}

		/// <summary>
		/// Gets the columns for this table.
		/// </summary>
		[Browsable(false)]
		public MethodCollection Methods
		{
			get
			{
				return _methods;
			}
		}

		public void MergeFrom(Table table)
		{
			this.SourceType = table.SourceType;

			// remove old columns

			for (int i = Columns.Count; i > 0; i--)
			{
				Column c = table.Columns.Find(Columns[0].Name);

				if (c == null)
				{
					Columns.RemoveAt(0);
					i--;
				}
			}

			// add new columns

			foreach (Column newColumn in table.Columns)
			{
				Column oldColumn = Columns.Find(newColumn.Name);

				if (oldColumn == null)
					this.Columns.Add(newColumn);
				else
					oldColumn.MergeFrom(newColumn);
			}

			// reorder

			ColumnCollection unordered = new ColumnCollection(this);
			unordered.AddRange(Columns);
			Columns.Clear();

			foreach (Column newColumn in table.Columns)
				Columns.Add(unordered.Find(newColumn.Name));
		}

		#region Xml Persistence

		internal static Table LoadFromXml(XPathNavigator navigator)
		{
			string uri = navigator.NamespaceURI;

			string uniqueid = navigator.GetAttribute("uniqueid", uri);
			string schema = navigator.GetAttribute("schema", uri);
			string name = navigator.GetAttribute("name", uri);
			string st = navigator.GetAttribute("sourceType", uri);
			TableSourceType sourceType = (TableSourceType)Enum.Parse(typeof(TableSourceType), st, true);

			string alias = navigator.GetAttribute("alias", uri);
			string comments = navigator.GetAttribute("comments", uri);
			bool canExport = navigator.SelectSingleNode("@canExport").ValueAsBoolean;

			CustomAttributes ca = CustomAttributes.LoadXml(navigator);

			Table t = new Table();

			if (!String.IsNullOrEmpty(uniqueid))
				t.UniqueID = new Guid(uniqueid);

			t.Schema = schema;
			t.Name = name;
			t.SourceType = sourceType;

			t.Alias = alias;
			t.Comments = comments;
			t.CanExport = canExport;

			XPathNodeIterator ni = navigator.Select("columns/column");

			while (ni.MoveNext())
			{
				Column c = Column.LoadFromXml(ni.Current);
				t.Columns.Add(c);
			}

			ni = navigator.Select("methods/method");
			while (ni.MoveNext())
			{
				Method m = Method.LoadFromXml(ni.Current);
				t.Methods.Add(m);
			}

			return t;
		}

		internal void SaveToXml(XmlWriter writer)
		{
			writer.WriteStartElement("table");

			writer.WriteAttributeString("uniqueid", UniqueID.ToString());

			// write table attributes
			if (!String.IsNullOrEmpty(Schema))
				writer.WriteAttributeString("schema", Schema);

			writer.WriteAttributeString("name", Name);
			writer.WriteAttributeString("sourceType", SourceType.ToString());

			if (!String.IsNullOrEmpty(Alias))
				writer.WriteAttributeString("alias", Alias);

			writer.WriteAttributeString("canExport", CanExport ? "1" : "0");

			if (!String.IsNullOrEmpty(Comments))
			{
				writer.WriteStartElement("comments");
				writer.WriteString(Comments);
				writer.WriteEndElement();
			}

			// write columns
			if (Columns.Count > 0)
			{
				writer.WriteStartElement("columns");

				foreach (Column c in Columns)
					c.SaveToXml(writer);
				
				writer.WriteEndElement();
			}

			// write methods
			if (Methods.Count > 0)
			{
				writer.WriteStartElement("methods");
				
				foreach (Method m in Methods)
					m.SaveToXml(writer);

				writer.WriteEndElement();
			}


			// write custom attributes
			CustomAttributes.SaveXml(writer);

			writer.WriteEndElement();
		}

		#endregion
	}
}
